<template>
  <div ref="tableWrapRef" class="baseTable p4">
    <HeaderTool
      :baseSetting="baseSetting"
      :columnTree="columnTree"
      :columnTreeLock="columnTreeLock"
      :initConfigList="initConfigList"
      @changeBaseSetting="
        (value) => {
          baseSetting = value;
        }
      "
      @reDrawColumn="reDrawColumn"
      @refreshTable="refreshTable"
      @fullScreen="fullScreen"
    >
      <template v-for="(_, name) in $slots" #[name]="data">
        <slot :name="name" v-bind="data"></slot>
      </template>
    </HeaderTool>
    <div class="main">
      <el-table
        ref="tableRef"
        style="width: 100%"
        v-bind="tableBind"
        :key="tableVersion"
        @select="
          (...args) => {
            emit('select', ...args);
          }
        "
        @select-all="
          (...args) => {
            emit('select-all', ...args);
          }
        "
        @selection-change="
          (...args) => {
            emit('selection-change', ...args);
          }
        "
        @cell-mouse-enter="
          (...args) => {
            emit('cell-mouse-enter', ...args);
          }
        "
        @cell-mouse-leave="
          (...args) => {
            emit('cell-mouse-leave', ...args);
          }
        "
        @cell-click="
          (...args) => {
            emit('cell-click', ...args);
          }
        "
        @cell-dblclick="
          (...args) => {
            emit('cell-dblclick', ...args);
          }
        "
        @cell-contextmenu="
          (...args) => {
            emit('cell-contextmenu', ...args);
          }
        "
        @row-click="
          (...args) => {
            emit('row-click', ...args);
          }
        "
        @row-contextmenu="
          (...args) => {
            emit('row-contextmenu', ...args);
          }
        "
        @row-dblclick="
          (...args) => {
            emit('row-dblclick', ...args);
          }
        "
        @header-click="
          (...args) => {
            emit('header-click', ...args);
          }
        "
        @header-contextmenu="
          (...args) => {
            emit('header-contextmenu', ...args);
          }
        "
        @sort-change="
          (...args) => {
            emit('sort-change', ...args);
          }
        "
        @filter-change="
          (...args) => {
            emit('filter-change', ...args);
          }
        "
        @current-change="
          (...args) => {
            emit('current-change', ...args);
          }
        "
        @header-dragend="
          (...args) => {
            emit('header-dragend', ...args);
          }
        "
        @expand-change="
          (...args) => {
            emit('expand-change', ...args);
          }
        "
      >
        <template #default>
          <column> </column>
        </template>
        <template #append="data">
          <slot name="append" v-bind="data"></slot>
        </template>

        <template #empty="data">
          <slot name="empty" v-bind="data"></slot>
        </template>
      </el-table>
    </div>
  </div>
</template>
<script setup lang="tsx">
import { ColumnProps, _Align, BaseSetting } from "./interface/types";
import { type TableProps } from "element-plus";
import HeaderTool from "@/components/baseTable/cps/headerTool.vue";
import treeTool from "@/utils/tree";
import screenfull from "screenfull";
import { isArray } from "@/utils/is";
import lodash from "lodash";

const emit = defineEmits([
  "refreshTable",
  "select",
  "select-all",
  "selection-change",
  "cell-mouse-enter",
  "cell-mouse-leave",
  "cell-click",
  "cell-dblclick",
  "cell-contextmenu",
  "row-click",
  "row-contextmenu",
  "row-dblclick",
  "header-click",
  "header-contextmenu",
  "sort-change",
  "filter-change",
  "current-change",
  "header-dragend",
  "expand-change",
]);

// ===============================================================================
// = type
interface TableProProps<T = any> extends TableProps<T> {
  align?: "left" | "center" | "right"; //整体对齐方式
}

// ===============================================================================
// = tool
const getDlotDefaultsTree = (slot: any, parentId?: any) => {
  const v = slot.default ? slot.default() : [];
  console.log(slot);

  const res = v.map((item: any, index: number) => {
    const isElColumn = item.type.name == "ElTableColumn";
    if (!item.props) {
      item.props = {};
    }

    if (isElColumn) {
      if (!item.props.prop && isElColumn) {
        item.props.prop = (parentId || "") + index;
      }
      if (!item.props.label && !item.props.type) {
        item.props.label = item.props.prop;
      }
      if (item.props.type && !item.props.label) {
        switch (item.props.type) {
          case "index":
            item.props.label = "索引";
            break;
          case "selection":
            item.props.label = "多选";
            break;
          case "expand":
            item.props.label = "展开";
            break;
          default:
            break;
        }
      }
      if (
        item.children &&
        item.children.default &&
        isArray(item.children.default()) &&
        item.children.default().length > 0 &&
        item.children.default()[0].type.name !== "ElTableColumn"
      ) {
        item.props.isCustomDom = true;
      }
    }

    item.id = item.props.prop;
    item.props._isShow = true;
    doms.push(item);

    return {
      ...item,
      children:
        item.children && item.children.default
          ? getDlotDefaultsTree(item.children, item.id)
          : item.children,
    };
  });
  return [
    ...res.filter((item: any) => item.props.fixed == "left"),
    ...res.filter((item: any) => !item.props.fixed),
    ...res.filter((item: any) => item.props.fixed == "right"),
  ];
};
const getInitConfig = (v: any): any => {
  if (!isArray(v)) {
    return null;
  }
  return v.map((item: any) => {
    return {
      props: item.props,
      children: item.children && getInitConfig(item.children),
    };
  });
};
const setTableSettingsVo = (
  props: Omit<TableProProps, "data">
): BaseSetting => {
  return {
    align: props.align || "left",
  };
};

const setColumnTreeVo = (columnTree: any[]): ColumnProps[] => {
  return columnTree.map<ColumnProps>((item: any) => {
    return {
      ...item.props,
      children: item.children && setColumnTreeVo(item.children || []),
    };
  });
};

// ===============================================================================
// = data

const props = withDefaults(defineProps<TableProProps>(), {
  indexColumn: false,
  align: "left",
  fit: true,
  showHeader: true,
  selectOnIndeterminate: true,
  indent: 16,
  treeProps: () => {
    return {
      hasChildren: "hasChildren",
      children: "children",
    };
  },
  style: () => ({}),
  className: "",
  tableLayout: "fixed",
  scrollbarAlwaysOn: false,
});

const doms: any[] = [];
const tableWrapRef = ref<any>();
const tableRef = ref<any>();
const baseSetting = ref<BaseSetting>(setTableSettingsVo(props));
const columnTreeLock: any[] = getDlotDefaultsTree(useSlots()); //可能会变化的
treeTool.addParentId(columnTreeLock);

const initConfigList = lodash.cloneDeep(
  treeTool
    .toList(getInitConfig(columnTreeLock))
    .filter((item) => item.props.prop)
);

const columnTree = ref<any[]>(getDlotDefaultsTree(useSlots())); //可能会变化的
treeTool.addParentId(columnTree);

const tableVersion = ref(0);
const tableBind = computed(() => {
  return {
    ...props,
    ...baseSetting.value,
  };
});
const isFull = ref(false);

// ===============================================================================
// = tsx

const column = () => {
  const createColumnVNode = (vNodes: any[]) => {
    return vNodes.map((vnode) => {
      const dom = doms.find((item) => item.id == vnode.id);
      //覆盖属性
      dom.props = vnode.props;
      return (
        vnode.props._isShow && (
          <dom>
            {{
              default: (scope: any) => {
                if (vnode.type.name == "ElTableColumn") {
                  if (vnode.props.isCustomDom) {
                    return dom.children.default(scope);
                  }
                  return (
                    vnode.children &&
                    isArray(vnode.children) &&
                    createColumnVNode(vnode.children)
                  );
                }
                return vnode.children;
              },
              header: dom.children && dom.children.header,
            }}
          </dom>
        )
      );
    });
  };

  const res = createColumnVNode(columnTree.value);
  return res;
};

// ===============================================================================
// = methods
const reDrawColumn = (columnTreeChange: any[]) => {
  columnTree.value = columnTreeChange;
  tableVersion.value++;
};
const refreshTable = () => {
  emit("refreshTable", {});
};
const fullScreen = () => {
  if (!screenfull.isEnabled) {
    return false;
  }
  if (!isFull.value) {
    screenfull.request(tableWrapRef.value); // 开启全屏
    isFull.value = true;
  } else {
    screenfull.toggle();
    isFull.value = false;
  }
};

//把el-table 的方法全部发布出去
defineExpose({
  clearSelection: (...args: any[]) => {
    return tableRef.value.clearSelection(...args);
  },
  getSelectionRows: (...args: any[]) => {
    return tableRef.value.getSelectionRows(...args);
  },
  toggleRowSelection: (...args: any[]) => {
    return tableRef.value.toggleRowSelection(...args);
  },
  toggleAllSelection: (...args: any[]) => {
    return tableRef.value.toggleAllSelection(...args);
  },
  toggleRowExpansion: (...args: any[]) => {
    return tableRef.value.toggleRowExpansion(...args);
  },
  setCurrentRow: (...args: any[]) => {
    return tableRef.value.setCurrentRow(...args);
  },
  clearSort: (...args: any[]) => {
    return tableRef.value.clearSort(...args);
  },
  clearFilter: (...args: any[]) => {
    return tableRef.value.clearFilter(...args);
  },
  doLayout: (...args: any[]) => {
    return tableRef.value.doLayout(...args);
  },
  sort: (...args: any[]) => {
    return tableRef.value.sort(...args);
  },
  scrollTo: (...args: any[]) => {
    return tableRef.value.scrollTo(...args);
  },
  setScrollTop: (...args: any[]) => {
    return tableRef.value.setScrollTop(...args);
  },
  setScrollLeft: (...args: any[]) => {
    return tableRef.value.setScrollLeft(...args);
  },
});
</script>

<style scoped lang="scss">
.baseTable {
  background-color: var(--background-color-base);
}
</style>
